package com.zyg.zlib.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @author zyg
 * <p>
 * 继承GradientDrawable，效果是否更好？
 */
public class LableDrawable extends Drawable {

    private float width;
    private float height;
    Drawable icon;
    private String text;
    private float textStartX;
    private float textStartY;
    private Paint fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private Path mPath = new Path();
    private boolean stroke;

    public static class Builder extends LableBuilder<LableDrawable.Builder, LableDrawable> {

        public static Builder newBuilder(Context context) {
            return new Builder(context);
        }

        Builder(Context context) {
            super(context);
        }

        @Override
        public LableDrawable build() {
            return new LableDrawable(this);
        }
    }


    LableDrawable(LableBuilder builder) {
        this.icon = builder.icon;
        this.text = builder.text;
        float iconWidth = 0;
        float iconHeight = 0;
        if (icon != null) {
            iconWidth = icon.getIntrinsicWidth() * builder.iconScale;
            iconHeight = icon.getIntrinsicHeight() * builder.iconScale;
        }
        if (!TextUtils.isEmpty(text)) {
            textPaint.setFakeBoldText(builder.textBold);
            textPaint.setTextSize(builder.textSize);
            textPaint.setColor(builder.textColor);
            Rect rect = new Rect();
            textPaint.getTextBounds(text, 0, text.length(), rect);
            width = builder.leftPadding + builder.gap + iconWidth + rect.width() + builder.rightPading;
            height = builder.topPadding + Math.max(iconHeight, rect.height()) + builder.bottomPadding;
            Paint.FontMetrics fm = textPaint.getFontMetrics();
            textStartX = builder.leftPadding + builder.gap + iconWidth;
            textStartY = height / 2 + (fm.descent - fm.ascent) / 2 - fm.descent;
        } else {
            width = builder.leftPadding + iconWidth + builder.rightPading;
            height = builder.topPadding + iconHeight + builder.bottomPadding;
        }
        RectF rect = new RectF();
        stroke = builder.stroke;
        if (stroke) {
            //解决锯齿问题，参考GradientDrawable
            float inset = builder.strokeWidth * 0.5f;
            rect.set(inset, inset, width - inset, height - inset);
        } else {
            rect = new RectF(0, 0, width, height);
        }
        float[] rids = new float[]{builder.leftTopRadius, builder.leftTopRadius, builder.rightTopRadius, builder.rightTopRadius,
                builder.rightBottomRadius, builder.rightBottomRadius, builder.leftBottomRadius, builder.leftBottomRadius};
        mPath.addRoundRect(rect, rids, Path.Direction.CW);

        if (icon != null) {
            float iconTop = (height - iconHeight) / 2;
            icon.setBounds(builder.leftPadding, (int) iconTop, (int) (builder.leftPadding + iconWidth), (int) (iconTop + iconHeight));
        }

        if (builder.gradient) {
            LinearGradient linearGradient = null;
            int startColor = builder.gradientStartColor;
            int endColor = builder.gradientEndColor;
            switch (builder.gradientDirection) {
                case 0:
                    linearGradient = new LinearGradient(0, 0, width, 0, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 45:
                    linearGradient = new LinearGradient(0, height, width, 0, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 90:
                    linearGradient = new LinearGradient(0, height, 0, 0, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 135:
                    linearGradient = new LinearGradient(width, height, 0, 0, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 180:
                    linearGradient = new LinearGradient(width, 0, 0, 0, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 225:
                    linearGradient = new LinearGradient(width, 0, 0, height, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 270:
                    linearGradient = new LinearGradient(0, 0, 0, height, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
                case 315:
                    linearGradient = new LinearGradient(0, 0, width, height, startColor, endColor, Shader.TileMode.CLAMP);
                    break;
            }

            if (linearGradient != null) {
                fillPaint.setShader(linearGradient);
            }
        } else {
            if (builder.fillColor != -1) {
                fillPaint.setColor(builder.fillColor);
            } else {
                fillPaint.setColor(Color.TRANSPARENT);
            }
        }
        if (stroke) {
            strokePaint.setStrokeWidth(builder.strokeWidth);
            strokePaint.setColor(builder.strokeColor);
            strokePaint.setPathEffect(null);
        }
    }


    /**
     * @return
     */
    @Override
    public int getIntrinsicWidth() {
        return (int) width;
    }

    @Override
    public int getIntrinsicHeight() {
        return (int) height;
    }

    private void ensurePaints() {
        fillPaint.setStyle(Paint.Style.FILL);
        strokePaint.setStyle(Paint.Style.STROKE);
        fillPaint.setAntiAlias(true);
//        fillPaint.setDither(true);
        strokePaint.setAntiAlias(true);
//        strokePaint.setDither(true);
    }

    /**
     * @param canvas
     */
    @Override
    public void draw(@NonNull Canvas canvas) {
        ensurePaints();
        canvas.drawPath(mPath, fillPaint);
        if (stroke) {
            canvas.drawPath(mPath, strokePaint);
        }
        if (icon != null) {
            icon.draw(canvas);
        }
        if (!TextUtils.isEmpty(text)) {
            canvas.drawText(text, textStartX, textStartY, textPaint);
        }
    }

    @Override
    public void setAlpha(int alpha) {

    }

    @Override
    public void setColorFilter(@Nullable ColorFilter colorFilter) {

    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSPARENT;
    }

}
